﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using mil.AnotoPen;
using mil.conoto;
using System.Windows.Input;
using System.Windows;
using System.Runtime.InteropServices;
using System.Windows.Threading;
using System.Threading;

namespace TabletopWidgetTestApp.Anoto
{
    class AnotoPenDriver
    {
        [DllImport("user32.dll")]
        static extern bool SetCursorPos(int X, int Y);

        [DllImport("user32.dll")]
        static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);

        [Flags]
        private enum MouseEventFlags
        {
            LEFTDOWN = 0x00000002,
            LEFTUP = 0x00000004,
            MIDDLEDOWN = 0x00000020,
            MIDDLEUP = 0x00000040,
            MOVE = 0x00000001,
            ABSOLUTE = 0x00008000,
            RIGHTDOWN = 0x00000008,
            RIGHTUP = 0x00000010
        }

        private AnotoStreamingServer anotoServer;
        private static ConotoElementManager manager;
        private static ConotoConvert conoto;

        private UIElement layoutRoot;

        public AnotoPenDriver(UIElement root)
        {
            layoutRoot = root;
        }

        public void Init()
        {
            // Initialize configuration
            manager = new ConotoElementManager();

            // Load config file created by MultiPatternConfigurator (or any other conoto config tool)
            // In this example the configuration file is stored in the folder "config".
            // This file maps the A4 sized Anoto-Pattern-Page "70.0.0.1" to a 1024x768 sized screen area.
            manager.LoadConfigFile("config/PatternConfig.pcf.xml");

            // Initialize event converter (needs the element manager that holds the configuration)
            conoto = new ConotoConvert(manager);

            // Initialize AnotoPen with the license key
            mil.AnotoPen.AnotoPen.Initialize("71ad1f27386ec4f5d91e15eca16f46c4");

            // Initialize the real-time streaming receiver of AnotoPen
            anotoServer = new AnotoStreamingServer();
            // Add event handler to receive pen up/down/move events.
            anotoServer.OnStroke += new AnotoStreamingServer.AnotoEventHandler(anotoServer_OnStroke);
            // Start receiver
            anotoServer.Start();
        }
        public void Dispose(bool value)
        {
            // Stop receiver and dispose AnotoPen assembly. 
            // Otherwise the receiver thread will not be killed and the application process would
            // be still running after exit.
            anotoServer.Stop();
            mil.AnotoPen.AnotoPen.Dispose();
        }

        private void anotoServer_OnStroke(object sender, AnotoPenEvent args)
        {
            // Events to raise: MouseMove, PreviewMouseDown, MouseDown, PreviewMouseUp, MouseUp.
            

            // Initialize some variables onto the conoto converter will write to.
            string function; // function string of the area hit by the pen (as configured in configuration)
            long functionid; // function id of the area hit by the pen (as configured in configuration)
            double x, y; // converted x/y coordinates

            // convert AnotoPen coordiantes to the configured ones (in this case, screen coordinates)
            conoto.Convert((ulong)args.PageId, args.X, args.Y,
                           out function, out functionid, out x, out y);
            SetCursorPos((int)x, (int)y);

            switch (args.Type)
            {
                case AnotoPenEventType.StrokeStart:
                    layoutRoot.Dispatcher.Invoke(DispatcherPriority.Send, (ThreadStart)delegate{
                        mouse_event((uint)MouseEventFlags.LEFTDOWN, (uint)x, (uint)y, 0, 0);
                    });
                    //mouse_event((uint)MouseEventFlags.LEFTUP, (uint)x, (uint)y, 0, 0);
                    break;
                case AnotoPenEventType.StrokeDrag:
                    layoutRoot.Dispatcher.Invoke(DispatcherPriority.Send, (ThreadStart)delegate{
                        mouse_event((uint)MouseEventFlags.MOVE, (uint)x, (uint)y, 0, 0);
                    });
                    break;
                case AnotoPenEventType.StrokeEnd:
                    layoutRoot.Dispatcher.Invoke(DispatcherPriority.Send, (ThreadStart)delegate { 
                        mouse_event((uint)MouseEventFlags.LEFTUP, (uint)x, (uint)y, 0, 0);
                    });
                    break;
            }
        }
    }
}
